#ifndef _SQL_COMPILER_
#define _SQL_COMPILER_

#include <string>
#include <cstring>

#include "results.h"
#include "Node.h"

class split {
public:
    split(char* s, char c = ' '): start_pos(0), max_pos(0), source(s), split_char(c) {
        for (int i = 0; source[i] != '\0'; i++, max_pos++) {
            if (source[i] == split_char) {
                source[i] = '\0';
            }
        }
    }
    const char* operator() () {
        if (start_pos >= max_pos) return nullptr;
        int pos = start_pos;

        while (source[start_pos] != '\0') start_pos++;
        start_pos++;

        return source + pos;
    }
private:
    int start_pos;
    int max_pos;
    char* source;
    char split_char;
};

class SQLCompiler {
public:
    CompileResult compile(std::string& input_buffer) {
        CompileResult result;

        if (input_buffer[0] == '.') {
            result.meta_result = do_meta_command(input_buffer);
        }

        result.prepare_result = prepare_statement(input_buffer, result.state);
        
        return result;
    }
private:
    MetaCommandResult do_meta_command(std::string& input_buffer) {
        if (input_buffer == ".exit") {
            return MetaCommandResult::Exit;
        } else if(input_buffer == ".constants") {
            printf("Constants:\n");
            print_constants();
            return MetaCommandResult::Success;
        } else {
            return MetaCommandResult::UnrecognizedCommand;
        }
    }
    PrepareResult prepare_statement(std::string& input_buffer, 
                                    Statement& statement) {
        if (input_buffer == "btree") {
            statement.type = StatementType::BTree;
            return PrepareResult::Success;
        }
        auto start_with = [&](const char* keyword) {
            for (int i = 0; keyword[i] && input_buffer[i]; i++) {
                if (keyword[i] != input_buffer[i]) return false;
            }
            return true;
        };
        if (start_with("insert")) {
            return prepare_insert(input_buffer, statement);
        } else if (start_with("select")) {
            statement.type = StatementType::Select;
            return PrepareResult::Success;
        }

        return PrepareResult::UnrecognizedStatement;
    }
    PrepareResult prepare_insert(std::string& input_buffer, 
                                    Statement& statement) {
        statement.type = StatementType::Insert;
        split split_by_space((char*)(input_buffer.c_str()));

        const char* keyword = split_by_space();
        const char* id_string = split_by_space();
        const char* username = split_by_space();
        const char* email = split_by_space();

        if (id_string == nullptr || username == nullptr || email == nullptr) 
            return PrepareResult::SyntaxError;
        
        int id = std::atoi(id_string);
        if (id <= 0) {
            return PrepareResult::NegativeID;
        }
        if (strlen(username) > COLUMN_USERNAME_SIZE || strlen(email) > COLUMN_EMAIL_SIZE) {
            return PrepareResult::StringTooLong;
        }

        statement.row_to_insert.id = id;
        strcpy(statement.row_to_insert.username, username);
        strcpy(statement.row_to_insert.email, email);

        return PrepareResult::Success;
    }
};

#endif